package scau.hotel.hotel_service.service.impl;

import com.github.pagehelper.PageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import scau.hotel.hotel_model.controller.RespBean;
import scau.hotel.hotel_model.controller.RespBeanEnum;
import scau.hotel.hotel_model.redis.RedisCache;
import scau.hotel.hotel_service.entity.*;
import scau.hotel.hotel_service.mapper.*;
import scau.hotel.hotel_service.service.CheckinInforService;
import scau.hotel.hotel_service.service.PaymentService;
import scau.hotel.hotel_service.util.SerialNoUtil;
import scau.hotel.hotel_service.vo.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * (CheckinInfor)表服务实现类
 *
 * @author makejava
 * @since 2022-03-28 20:18:11
 */
@Service("checkinInforService")
public class CheckinInforServiceImpl implements CheckinInforService {

    Map<String, List<CheckinInfor>> checkinInforCache = new HashMap<>(); //入住明细表缓存数据
    Map<String, Object> checkinCache = new HashMap<String, Object>();                 //入住表缓存数据
    Map<String, List<CheckinCusInfor>> cusInforCache = new HashMap<>(); //入住人信息缓存数据
    Map<String, List<CheckinCusInfor>> chooseCusCache = new HashMap<>(); //存储要返回待选择的入住人信息缓存数据
    Map<String, List<Payment>> paymentCache = new HashMap<>();           //支付表缓存
    private boolean noCus = true;            //判断是否有客人已登记但未入住，默认没有为true


    @Resource
    private CheckinInforMapper checkinInforMapper;

    @Resource
    private CheckinCusInforMapper checkinCusInforMapper;

    @Resource
    private CheckinMapper checkinMapper;

    @Resource
    private RoomMapper roomMapper;

    @Resource
    private RoomTypeMapper roomTypeMapper;

    @Resource
    private PaymentMapper paymentMapper;

    @Resource
    private BookMapper bookMapper;

    @Resource
    private PaymentService paymentService;

    @Resource
    private RedisCache redisCache;

    /**
     * 通过ID查询单条数据
     *
     * @param checkinInforId 主键
     * @return 实例对象
     */
    @Override
    public CheckinInfor queryById(Integer checkinInforId) {
        CheckinInfor checkinInfor = this.checkinInforMapper.queryById(checkinInforId);
        //给返回结果的房费跟押金赋值
        checkinInfor.setRoomPrice(this.paymentMapper.queryRoomPrice(checkinInfor.getCheckinInforId()).getAmount());
        if(this.paymentMapper.queryCashPledge(checkinInfor.getCheckinInforId())==null){
            checkinInfor.setCashPledge(BigDecimal.valueOf(0));
        }else {
            checkinInfor.setCashPledge(this.paymentMapper.queryCashPledge(checkinInfor.getCheckinInforId()).getAmount());
        }
        return checkinInfor;
    }


    /**
     * 新增数据
     *
     * @param checkinInfor 实例对象
     * @return 实例对象
     */
    @Override
    public RespBean insert(CheckinInfor checkinInfor) {
        this.checkinInforMapper.insert(checkinInfor);
        return RespBean.success();
    }

    /**
     * 修改数据
     *
     * @param checkinInfor 实例对象
     * @return 实例对象
     */
    @Override
    public RespBean update(CheckinInfor checkinInfor) {
        if(checkinInfor.getDelFlag()==0 && Objects.equals(this.checkinInforMapper.queryById(checkinInfor.getCheckinInforId()).getStatus(), "入住中")){
            return RespBean.error(RespBeanEnum.CHECKIN_INFO_STATUS_ERROR);
        }else {
            this.checkinInforMapper.update(checkinInfor);
            return RespBean.success();
        }
    }

    /**
     * 通过主键删除数据
     *
     * @param checkinInforId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer checkinInforId) {
        return this.checkinInforMapper.deleteById(checkinInforId) > 0;
    }

    /**
     * 查询所有数据
     *
     * @param checkinInfor 筛选条件
     * @return 查询结果
     */
    @Override
    public List<CheckinInfor> queryAll(CheckinInfor checkinInfor) {
        return this.checkinInforMapper.queryAll(checkinInfor);
    }

    /**
     * 分页查询所有数据
     *
     * @param checkinInfor 筛选条件
     * @return 查询结果
     */
    @Override
    public List<CheckinInfor> queryAllByPage(Integer pageNum, Integer pageSize, CheckinInfor checkinInfor) {
        PageHelper.startPage(pageNum, pageSize);
        List<CheckinInfor> cInforList = this.checkinInforMapper.queryAll(checkinInfor);
        return this.query(cInforList);
    }

    /**
     * 不分页查询当前时间后退房的数据
     *
     * @return RespBean
     */
    @Override
    public RespBean queryNowCheckinInforNoPage(){
//        Date date=new Date();//此时date为当前的时间
////        Timestamp time = new Timestamp(System.currentTimeMillis());//获取当前时间对象，"yyyy-MM-dd HH:mm:ss"
//        SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");//设置当前时间的格式，为年-月-日
//        Date checkoutDate = new Date();
//        try {
//            checkoutDate = dateFormat.parse(dateFormat.format(date)); // 把上面的字符串解析为日期类型
//        } catch (ParseException e) {
//            e.printStackTrace();
//        }
        List<CheckinInfor> cInforList = this.checkinInforMapper.queryCheckinInfor();
        return RespBean.success(this.query(cInforList));
    }

    /**
     * 分页入住中数据
     *
     * @return 实例对象
     */
    @Override
    public List<CheckinInfor> queryNowCheckinInfor(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<CheckinInfor> cInforList = this.checkinInforMapper.queryCheckinInfor();
        return this.query(cInforList);
    }


    /**
     * 根据roomNo查询数据
     *
     * @param roomNo 筛选条件
     * @return RespBean
     */
    @Override
    public RespBean queryCheckinInforByRoomNo(String roomNo) {
        if(this.roomMapper.queryRoomByRoomNo(roomNo)==null){
            return RespBean.error(RespBeanEnum.ROOM_NO_NOT_EXIST_ERROR);
        }else {
            Integer roomId = this.roomMapper.queryRoomByRoomNo(roomNo).getRoomId();
            if(this.checkinInforMapper.queryCheckinInforByRoomId(roomId).size()==0){
                return RespBean.error(RespBeanEnum.CHECKIN_INFO_NOT_EXIST_ERROR);
            }else {
                List<CheckinInfor> cInforList = this.checkinInforMapper.queryCheckinInforByRoomId(roomId);
                return RespBean.success(this.query(cInforList));
            }
        }
    }


    /**
     *
     * 查询方法重复调用:调取订单明细的房费和押金
     */
    public List<CheckinInfor> query(List<CheckinInfor> cInforList){
        //给返回结果的房费跟押金赋值
        for (CheckinInfor checkinInforA : cInforList) {
            checkinInforA.setRoomPrice(this.paymentMapper.queryRoomPrice(checkinInforA.getCheckinInforId()).getAmount());
            if (this.paymentMapper.queryCashPledge(checkinInforA.getCheckinInforId()) == null) {
                checkinInforA.setCashPledge(BigDecimal.valueOf(0));
            } else {
                checkinInforA.setCashPledge(this.paymentMapper.queryCashPledge(checkinInforA.getCheckinInforId()).getAmount());
            }
        }
        return cInforList;
    }

    /**
     * 步骤1：登记客人信息
     * @param cusInforList
     * @return
     */
    @Override
    public RespBean doRegistered(List<CheckinCusInforVo> cusInforList) {
        //判断是否重复登记
        boolean notRepeat = true;
        for(int i = 0; i < cusInforList.size(); i++){
            for(int k = i + 1; k < cusInforList.size(); k++){
                if(cusInforList.get(i).getCusIdcard().equals(cusInforList.get(k).getCusIdcard())){
                    notRepeat = false;
                    break;
                }
            }
        }
        //如果没有重复登记
        if(notRepeat) {
            //判断是否有客人已登记信息但未入住的情况
            if (noCus) {
                //生成入住信息表缓存
                List<CheckinInfor> checkinInforList = new ArrayList<>();
                checkinInforCache.put("checkinInfor", checkinInforList);

                //生成入住人员信息表缓存
                List<CheckinCusInfor> checkinCusInforsList = new ArrayList<>();
                List<CheckinCusInfor> rCusInforsList = new ArrayList<>();
                this.addCusInList(cusInforList, checkinCusInforsList, rCusInforsList);
                cusInforCache.put("cusInfor", rCusInforsList);
//                redisCache.setCacheList("cusInfor", rCusInforsList);

                //生成待选择入住人员缓存
//                chooseCusCache.put("rCusInfor", checkinCusInforsList);
//                redisCache.setCacheList("rCusInfor", checkinCusInforsList);

                //自定义入住表id
                int checkinId = 0;
                if (this.checkinMapper.queryLastId() == null) {
                    checkinId = 1;
                } else {
                    checkinId = this.checkinMapper.queryLastId().getCheckinId() + 1;
                }
                //初始化入住表
                Integer cusNum = cusInforList.size();
                Integer roomNum = 0;
                //添加入住表进缓存
                checkinCache.put("checkinId", checkinId);
                checkinCache.put("checkinCusNum", cusNum);
                checkinCache.put("checkinRoomNum", roomNum);

                //生成支付表缓存
                List<Payment> paymentList = new ArrayList<>();
                paymentCache.put("payment", paymentList);

                //已有客人登记但未入住，noCus改为false
                noCus = false;
            } else {
                //新增入住人员信息
                List<CheckinCusInfor> newCusInforsList = cusInforCache.get("cusInfor");
//                List<CheckinCusInfor> newCusInforsList = redisCache.getCacheList("cusInfor");
//                List<CheckinCusInfor> rNewCusInforsList = chooseCusCache.get("rCusInfor");
                List<CheckinCusInfor> rNewCusInforsList = redisCache.getCacheList("rCusInfor");
                //判断缓存中是否存在相同人员信息
                for(int i = 0; i < cusInforList.size(); i++){
                    for(int k = i; k < newCusInforsList.size(); k++){
                        if(cusInforList.get(i).getCusIdcard().equals(newCusInforsList.get(k).getCheckinCusIdCard())){
                            notRepeat = false;
                            break;
                        }
                    }
                }
                if (notRepeat) {
                    this.addCusInList(cusInforList, newCusInforsList, rNewCusInforsList);
                }else{
                    return RespBean.error(RespBeanEnum.CUS_EXIST_ERROR);
                }
            }
            return RespBean.success();
        }else{
            return RespBean.error(RespBeanEnum.CUS_REPEAT_ERROR);
        }
    }

    /**
     * 步骤1：内嵌方法，添加入住人信息至缓存数组
     * @param cusInforList 前端传入的参数
     * @param checkinCusInforsList 准备插入数据库的入住人数组
     * @param rCusInforsList 用于返回前端的待选择入住人列表
     */
    public void addCusInList(List<CheckinCusInforVo> cusInforList,
                                              List<CheckinCusInfor> checkinCusInforsList,
                                              List<CheckinCusInfor> rCusInforsList){
        for (int i = 0; i < cusInforList.size(); i++) {
            CheckinCusInfor checkinCusInfor = new CheckinCusInfor();
            //获取姓名
            checkinCusInfor.setCheckinCusName(cusInforList.get(i).getCusName());
            //获取身份证
            checkinCusInfor.setCheckinCusIdCard(cusInforList.get(i).getCusIdcard());
            //获取电话号码
            checkinCusInfor.setCheckinCusTel(cusInforList.get(i).getCusTel());
            //设置备注
            checkinCusInfor.setRemark(cusInforList.get(i).getRemark());
            //设置删除标志，默认为1存在
            checkinCusInfor.setDelFlag(1);
            /*入住明细id在选择房间后勾选入住人时绑定*/
            checkinCusInforsList.add(checkinCusInfor);
            rCusInforsList.add(checkinCusInfor);
        }
        //先清除缓存，再重新存入
        redisCache.deleteObject("rCusInfor");
        redisCache.setCacheList("rCusInfor", rCusInforsList);
    }

    /**
     * 步骤2：选择房间,返回待入住人员
     *
     */
    @Override
    public RespBean returnCusList(GetPriceVo getPriceVo){
//        List<CheckinCusInfor> cusList = chooseCusCache.get("rCusInfor");
        List<CheckinCusInfor> cusList = redisCache.getCacheList("rCusInfor");
        //返回当前点击房间号和房间类型
        ReturnCusInfoVo returnCusInfoVo = new ReturnCusInfoVo();
        returnCusInfoVo.setRoomNo(this.roomMapper.queryById(getPriceVo.getRoomId()).getRoomNo());
        returnCusInfoVo.setRoomTypeName(this.roomMapper.queryById(getPriceVo.getRoomId()).getRoomType().getRoomTypeName());
        //判断为空则返回提醒
        if(CollectionUtils.isEmpty(cusList)) {
            return RespBean.error(RespBeanEnum.CHECKIN_CUS_NOT_EXIST_ERROR,returnCusInfoVo);
        }else {
            List<CheckinCusInforVo> cusListVo = new ArrayList<>();
            for (CheckinCusInfor checkinCusInfor : cusList) {
                CheckinCusInforVo checkinCusInforVo = new CheckinCusInforVo();
                checkinCusInforVo.setCusName(checkinCusInfor.getCheckinCusName());
                checkinCusInforVo.setCusIdcard(checkinCusInfor.getCheckinCusIdCard());
                checkinCusInforVo.setCusTel(checkinCusInfor.getCheckinCusTel());
                checkinCusInforVo.setRemark(checkinCusInfor.getRemark());
                cusListVo.add(checkinCusInforVo);
            }
            returnCusInfoVo.setCheckinCusInforVos(cusListVo);
            return RespBean.success(returnCusInfoVo);
        }
    }

    /**
     * 步骤2：选择房间,计算价格
     *
     */
    @Override
    public RespBean getPrice(GetPriceVo getPriceVo){
        //获取价格
        return this.paymentService.getFinalPrice(getPriceVo);
    }

    /**
     * 步骤2：生成支付表
     * @param getPriceVo 前端传回的Vo
     * @param checkinInforId 入住明细id
     * @return
     */
    public void generatePayment(GetPriceVo getPriceVo, Integer checkinInforId){
        List<Payment> paymentList = paymentCache.get("payment");
        Payment roomPrice =new Payment();
        /*生成房费数据*/
        //设置支付表的入住明细id
        roomPrice.setCheckinInforId(checkinInforId);
        //设置房费金额
        roomPrice.setAmount((BigDecimal)this.getPrice(getPriceVo).getData());
        //获取当前时间
        Date currenTime = new Date();
        //设置支付表支付时间
        roomPrice.setPayDate(currenTime);
        //设置支付表支付方式
        roomPrice.setPayWay(getPriceVo.getPayWay());
        //设置支付表费用标志：房费为1
        roomPrice.setFlag(1);
        //设置状态
        roomPrice.setStatus("已入账");
        //设置支付表备注
        roomPrice.setRemark(getPriceVo.getRemark());
        //设置删除标志，默认为1存在
        roomPrice.setDelFlag(1);
        paymentList.add(roomPrice);

        /*生成押金数据*/
        //浅拷贝对象
        Payment deposit = (Payment) roomPrice.clone();
        //重新设置支付时间
        deposit.setPayDate(new Date());
        //获取押金金额
        deposit.setAmount(getPriceVo.getCashPledge());
        //设置支付表费用标志：押金为0
        deposit.setFlag(0);
        //设置备注为空，除去冗余
        deposit.setRemark(null);
        //添加进数组
        paymentList.add(deposit);
        paymentCache.put("payment",paymentList);
    }

    /**
     * 步骤2：选择房间并勾选入住人,确认
     *
     */
    @Override
    public RespBean chooseRoom(GetPriceVo getPriceVo) {
        //初始化入住明细id
        Integer checkinInforId = 0;
        //获取勾选的入住人
        List<CheckinCusInforVo> checkinCusInforVos = getPriceVo.getMultipleSelection();
        if(CollectionUtils.isEmpty(checkinCusInforVos)){
            return RespBean.error(RespBeanEnum.CUS_UNCHECKED_ERROR);
        }else {
            //从缓存中获取数组
            List<CheckinInfor> checkinInforList = checkinInforCache.get("checkinInfor");
            List<CheckinCusInfor> checkinCusInforList = cusInforCache.get("cusInfor");
//            List<CheckinCusInfor> checkinCusInforList = redisCache.getCacheList("cusInfor");
            //获取入住信息id
            if (this.checkinInforMapper.queryLastId() == null) {
                checkinInforId = 1;
            } else {
                checkinInforId = this.checkinInforMapper.queryLastId().getCheckinInforId() + 1 + checkinInforList.size();
            }
            //新建入住明细对象
            CheckinInfor checkinInfor = new CheckinInfor();
            //设定入住信息id
            checkinInfor.setCheckinInforId(checkinInforId);
            //绑定入住id
            checkinInfor.setCheckinId((Integer) checkinCache.get("checkinId"));
            //获取入住房间id
            checkinInfor.setRoomId(getPriceVo.getRoomId());
            //获取入住时间
            checkinInfor.setCheckinDate(getPriceVo.getCheckinDate());
            //获取预定退房时间
            checkinInfor.setCheckoutDate(getPriceVo.getCheckoutDate());
            //设置状态
            checkinInfor.setStatus("入住中");
            //获取备注
            checkinInfor.setRemark(getPriceVo.getRemark());
            //设置删除标志，默认为1存在
            checkinInfor.setDelFlag(1);
            //为入住人员信息绑定入住明细id
            for (CheckinCusInforVo checkinCusInforVo : checkinCusInforVos) {
                for (int k = 0; k < checkinCusInforList.size(); k++) {
                    CheckinCusInfor checkinCusInfor = checkinCusInforList.get(k);
                    //匹配相同身份证的入住人
                    if (Objects.equals(checkinCusInforVo.getCusIdcard(), checkinCusInfor.getCheckinCusIdCard())) {
                        //绑定入住明细id
                        checkinCusInfor.setCheckinInforId(checkinInforId);
                        checkinCusInforList.set(k, checkinCusInfor);
                        //更新入住人员信息缓存
                        cusInforCache.put("cusInfor", checkinCusInforList);
//                        redisCache.setCacheList("cusInfor", checkinCusInforList);

                        //选择入住人列表中清除已办理入住的人员信息
//                        List<CheckinCusInfor> cusInfors = chooseCusCache.get("rCusInfor");
                        List<CheckinCusInfor> cusInfors = redisCache.getCacheList("rCusInfor");

                        //清除已登记入住的客人
                        for (int i = 0; i < cusInfors.size(); i++) {
                            if (cusInfors.get(i).getCheckinCusIdCard().equals(checkinCusInfor.getCheckinCusIdCard())){
                                cusInfors.remove(i);
                                break;
                            }
                        }
//                        chooseCusCache.put("rCusInfor", cusInfors);
                        //先清空再插入
                        redisCache.deleteObject("rCusInfor");
                        if (cusInfors.size()!=0) {
                            redisCache.setCacheList("rCusInfor", cusInfors);
                        }
                    }
                }
            }
            //生成支付表并绑定入住明细id
            this.generatePayment(getPriceVo, checkinInforId);
            //缓存数组新增入住明细对象
            checkinInforList.add(checkinInfor);
            //更新入住信息缓存
            checkinInforCache.put("checkinInfor", checkinInforList);
            //改变房间状态
            RoomVo roomVo = new RoomVo();
            Room room = roomMapper.queryById(getPriceVo.getRoomId());
            roomVo.setRoomId(room.getRoomId());
            roomVo.setRoomNo(room.getRoomNo());
            roomVo.setRoomState("待入住");
            roomVo.setRoomTypeId(room.getRoomTypeId());
            this.roomMapper.update(roomVo);

            return RespBean.success();
        }
    }

    /**
     * 步骤3：确认入住并将缓存插入数据库
     *
     */
    @Override
    public RespBean confirmCheckin() {
        if(noCus){
            return RespBean.error(RespBeanEnum.CHECKIN_CUS_NOT_EXIST_ERROR);
//        }else if(chooseCusCache.get("rCusInfor").size()!=0){
        }else if(redisCache.getCacheList("rCusInfor").size()!=0){
            return RespBean.error(RespBeanEnum.CUS_NOT_REGISTERED_ERROR);
        }
        else {
            SerialNoUtil serialNoUtil = new SerialNoUtil();
            //从缓存中获取数组
            List<CheckinInfor> checkinInforList = checkinInforCache.get("checkinInfor");
            List<CheckinCusInfor> checkinCusInforList = cusInforCache.get("cusInfor");
//            List<CheckinCusInfor> checkinCusInforList = redisCache.getCacheList("cusInfor");
            Checkin checkin = new Checkin();
            checkin.setCheckinId((Integer) this.checkinCache.get("checkinId"));
            checkin.setCheckinCusNum(checkinCusInforList.size());
            checkin.setCheckinRoomNum(checkinInforList.size());
            //入住表插入数据库
            this.checkinMapper.insert(checkin);
            //入住信息表插入数据库
            for (CheckinInfor checkinInfor : checkinInforList) {
                this.checkinInforMapper.insert(checkinInfor);
            }
            //入住人员表插入数据库
            for (CheckinCusInfor checkinCusInfor : checkinCusInforList) {
                this.checkinCusInforMapper.insert(checkinCusInfor);
            }
            //支付表插入数据库
            List<Payment> paymentList = paymentCache.get("payment");
            for (Payment payment : paymentList) {
                //生成流水号：押金流水号或房费流水号
                if (payment.getFlag() == 1) {
                    payment.setSerialNo(serialNoUtil.createSerialNo("FFNO", this.paymentMapper.querySecondToLast().getSerialNo()));
                } else {
                    payment.setSerialNo(serialNoUtil.createSerialNo("YJNO", this.paymentMapper.querySecondToLast().getSerialNo()));
                }
                this.paymentService.insert(payment);
            }
            //更改房间状态
            RoomVo roomVo = new RoomVo();
            for (CheckinInfor checkinInfor : checkinInforList) {
                Room room = roomMapper.queryById(checkinInfor.getRoomId());
                roomVo.setRoomId(room.getRoomId());
                roomVo.setRoomNo(room.getRoomNo());
                roomVo.setRoomState("已入住");
                roomVo.setRoomTypeId(room.getRoomTypeId());
                this.roomMapper.update(roomVo);
            }
            //如果从预订接口处接入则更改预定表数据
            if (this.redisCache.keys("bookId").size()!=0) {
                Book book = this.bookMapper.queryById(this.redisCache.getCacheObject("bookId"));
                book.setStatus("已入住");
                this.bookMapper.update(book);
            }
            //清空缓存
            this.removeCache();
            System.out.println("欢迎入住wushan豪华大酒店");
            return RespBean.success();
        }
    }

    /**
     * 清楚缓存，取消入住
     *
     */
    @Override
    public RespBean removeCache() {
        //客人登记已入住或取消登记，flag改为false
        noCus = true;
        //清空所有缓存
        checkinInforCache.clear();
        checkinCache.clear();
//        chooseCusCache.clear();
        redisCache.deleteObject("rCusInfor");
        cusInforCache.clear();
//        redisCache.deleteObject("cusInfor");
        paymentCache.clear();
        redisCache.deleteObject("bookId");
        return RespBean.success("缓存已清空");
    }

    /**
     * 按图书类别id统计借阅数
     * @return 结果集合
     */
    @Override
    public List<DashboardVo> countByRoomTypeId(){
        List<RoomType> typeList = this.roomTypeMapper.queryAll(new RoomType());
        List<DashboardVo> dashboardVoList = new ArrayList<>();
        for(RoomType roomType : typeList){
            DashboardVo dashboardVo = new DashboardVo();
            long count = this.checkinInforMapper.countByRoomTypeId(roomType.getRoomTypeId());
            String name = roomType.getRoomTypeName();
            dashboardVo.setValue(count);
            dashboardVo.setName(name);
            dashboardVoList.add(dashboardVo);
        }
        return dashboardVoList;
    };

}
